}
static void
-gtk_window_realize (GtkWidget *widget)
+sum_borders (GtkBorder *one,
+ GtkBorder *two)
{
- GtkAllocation allocation;
- GtkWindow *window;
- GdkWindow *parent_window;
- GdkWindow *gdk_window;
- GdkWindowAttr attributes;
- gint attributes_mask;
- GtkWindowPrivate *priv;
+ one->top += two->top;
+ one->right += two->right;
+ one->bottom += two->bottom;
+ one->left += two->left;
+}
+
+static void
+max_borders (GtkBorder *one,
+ GtkBorder *two)
+{
+ one->top = MAX (one->top, two->top);
+ one->right = MAX (one->right, two->right);
+ one->bottom = MAX (one->bottom, two->bottom);
+ one->left = MAX (one->left, two->left);
+}
+
+static void
+subtract_borders (GtkBorder *one,
+ GtkBorder *two)
+{
+ one->top -= two->top;
+ one->right -= two->right;
+ one->bottom -= two->bottom;
+ one->left -= two->left;
+}
+
+static void
+add_window_frame_style_class (GtkStyleContext *context)
+{
+ gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
+ gtk_style_context_add_class (context, "window-frame");
+}
+
+static void
+get_shadow_width (GtkWidget *widget,
+ GtkBorder *shadow_width)
+{
+ GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
+ GtkBorder border = { 0 };
+ GtkBorder d = { 0 };
+ GtkBorder margin;
+ GtkStyleContext *context;
+ GtkStateFlags state, s;
+ GtkCssValue *shadows;
gint i;
- GList *link;
- window = GTK_WINDOW (widget);
- priv = window->priv;
+ *shadow_width = border;
- if (!priv->client_decorated && gtk_window_should_use_csd (window))
- create_decoration (widget);
+ if (!priv->decorated ||
+ !priv->client_decorated)
+ return;
- gtk_widget_get_allocation (widget, &allocation);
+ if (priv->maximized ||
+ priv->fullscreen ||
+ priv->tiled)
+ return;
- if (gtk_widget_get_parent_window (widget))
- {
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
- G_GNUC_END_IGNORE_DEPRECATIONS;
+ state = gtk_widget_get_state_flags (widget);
+ context = gtk_widget_get_style_context (widget);
- attributes.x = allocation.x;
- attributes.y = allocation.y;
- attributes.width = allocation.width;
- attributes.height = allocation.height;
- attributes.window_type = GDK_WINDOW_CHILD;
+ gtk_style_context_save (context);
+ add_window_frame_style_class (context);
- attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+ /* We don't want windows to jump as they go to backdrop,
+ * therefore we use the maximum of the decoration sizes
+ * for focused and unfocused.
+ */
+ for (i = 0; i < 2; i++)
+ {
+ if (i == 0)
+ s = state & ~GTK_STATE_FLAG_BACKDROP;
+ else
+ s = state | GTK_STATE_FLAG_BACKDROP;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.wclass = GDK_INPUT_OUTPUT;
+ /* Always sum border + padding */
+ gtk_style_context_get_border (context, s, &border);
+ gtk_style_context_get_padding (context, s, &d);
+ sum_borders (&d, &border);
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+ /* Calculate the size of the drop shadows ... */
+ gtk_style_context_set_state (context, s);
+ shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW);
+ _gtk_css_shadows_value_get_extents (shadows, &border);
- gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
- &attributes, attributes_mask);
- gtk_widget_set_window (widget, gdk_window);
- gtk_widget_register_window (widget, gdk_window);
- gtk_widget_set_realized (widget, TRUE);
+ if (priv->type != GTK_WINDOW_POPUP)
+ {
+ /* ... and compare it to the margin size, which we use for resize grips */
+ gtk_style_context_get_margin (context, s, &margin);
+ max_borders (&border, &margin);
+ }
- return;
+ sum_borders (&d, &border);
+ max_borders (shadow_width, &d);
}
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
- G_GNUC_END_IGNORE_DEPRECATIONS;
+ gtk_style_context_restore (context);
+}
- /* ensure widget tree is properly size allocated */
- if (allocation.x == -1 &&
- allocation.y == -1 &&
- allocation.width == 1 &&
- allocation.height == 1)
- {
- gint w, h;
+/* We're placing 8 input-only windows around
+ * the window content as resize handles, as
+ * follows:
+ *
+ * +-----------------------------------+
+ * | +------+-----------------+------+ |
+ * | | | | | |
+ * | | +--+-----------------+--+ | |
+ * | | | | | |
+ * | +---+ +---+ |
+ * | | | | | |
+ * | | | | | |
+ * | | | | | |
+ * | +---+ +---+ |
+ * | | | | | |
+ * | | +--+-----------------+--+ | |
+ * | | | | | |
+ * | +------+-----------------+------+ |
+ * +-----------------------------------+
+ *
+ * The corner windows are shaped to allow them
+ * to extend into the edges. If the window is
+ * not resizable in both dimensions, we hide
+ * the corner windows and the edge windows in
+ * the nonresizable dimension and make the
+ * remaining edge window extend all the way.
+ *
+ * The border are where we place the resize handles
+ * is also used to draw the window shadow, which may
+ * extend out farther than the handles (or the other
+ * way around).
+ */
+static void
+update_border_windows (GtkWindow *window)
+{
+ GtkWidget *widget = (GtkWidget *)window;
+ GtkWindowPrivate *priv = window->priv;
+ gboolean resize_h, resize_v;
+ gint handle;
+ cairo_region_t *region;
+ cairo_rectangle_int_t rect;
+ gint width, height;
+ GtkBorder border;
+ GtkBorder window_border;
+ GtkStyleContext *context;
+ GtkStateFlags state;
- allocation.x = 0;
- allocation.y = 0;
+ if (!priv->client_decorated)
+ return;
- gtk_window_guess_default_size (window, &allocation.width, &allocation.height);
- gtk_window_get_remembered_size (window, &w, &h);
- allocation.width = MAX (allocation.width, w);
- allocation.height = MAX (allocation.height, h);
- if (allocation.width == 0 || allocation.height == 0)
- {
- /* non-empty window */
- allocation.width = 200;
- allocation.height = 200;
- }
- gtk_widget_size_allocate (widget, &allocation);
-
- _gtk_container_queue_resize (GTK_CONTAINER (widget));
+ state = gtk_widget_get_state_flags (widget);
+ context = gtk_widget_get_style_context (widget);
- g_return_if_fail (!gtk_widget_get_realized (widget));
- }
+ gtk_style_context_save (context);
+ add_window_frame_style_class (context);
+ gtk_style_context_set_state (context, state);
+ gtk_style_context_get_margin (context, state, &border);
+ gtk_widget_style_get (widget,
+ "decoration-resize-handle", &handle,
+ NULL);
+ gtk_style_context_restore (context);
+ get_shadow_width (widget, &window_border);
- if (priv->hardcoded_window)
+ if (priv->border_window[0] == NULL)
+ goto shape;
+
+ if (!priv->resizable ||
+ priv->tiled ||
+ priv->fullscreen ||
+ priv->maximized)
{
- gdk_window = priv->hardcoded_window;
- gtk_widget_get_allocation (widget, &allocation);
- gdk_window_resize (gdk_window, allocation.width, allocation.height);
+ resize_h = resize_v = FALSE;
}
else
{
- switch (priv->type)
+ resize_h = resize_v = TRUE;
+ if (priv->geometry_info)
{
- case GTK_WINDOW_TOPLEVEL:
- attributes.window_type = GDK_WINDOW_TOPLEVEL;
- break;
- case GTK_WINDOW_POPUP:
- attributes.window_type = GDK_WINDOW_TEMP;
- break;
- default:
- g_warning (G_STRLOC": Unknown window type %d!", priv->type);
- break;
- }
-
-#ifdef GDK_WINDOWING_WAYLAND
- if (priv->use_subsurface &&
- GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
- attributes.window_type = GDK_WINDOW_SUBSURFACE;
-#endif
+ GdkGeometry *geometry = &priv->geometry_info->geometry;
+ GdkWindowHints flags = priv->geometry_info->mask;
- attributes.title = priv->title;
- attributes.wmclass_name = priv->wmclass_name;
- attributes.wmclass_class = priv->wmclass_class;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gtk_widget_get_visual (widget);
+ if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE))
+ {
+ resize_h = geometry->min_width != geometry->max_width;
+ resize_v = geometry->min_height != geometry->max_height;
+ }
+ }
+ }
- attributes_mask = 0;
- parent_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
+ width = gtk_widget_get_allocated_width (widget) - (window_border.left + window_border.right);
+ height = gtk_widget_get_allocated_height (widget) - (window_border.top + window_border.bottom);
- gtk_widget_get_allocation (widget, &allocation);
- attributes.width = allocation.width;
- attributes.height = allocation.height;
- attributes.event_mask = gtk_widget_get_events (widget);
- attributes.event_mask |= (GDK_EXPOSURE_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_BUTTON_MOTION_MASK |
- GDK_KEY_PRESS_MASK |
- GDK_KEY_RELEASE_MASK |
- GDK_ENTER_NOTIFY_MASK |
- GDK_LEAVE_NOTIFY_MASK |
- GDK_FOCUS_CHANGE_MASK |
- GDK_STRUCTURE_MASK);
-
- if (priv->decorated &&
- (priv->client_decorated || priv->custom_title))
- attributes.event_mask |= GDK_POINTER_MOTION_MASK;
-
- attributes.type_hint = priv->type_hint;
-
- attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT;
- attributes_mask |= (priv->title ? GDK_WA_TITLE : 0);
- attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0);
-
- gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask);
- }
-
- gtk_widget_set_window (widget, gdk_window);
- gtk_widget_register_window (widget, gdk_window);
- gtk_widget_set_realized (widget, TRUE);
-
- /* We don't need to set a background on the GdkWindow; with decorations
- * we draw the background ourself
- */
- if (!priv->client_decorated)
- gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window);
+ if (resize_h && resize_v)
+ {
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
+ window_border.left - border.left, window_border.top - border.top,
+ border.left + handle, border.top + handle);
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
+ window_border.left + width - handle, window_border.top - border.top,
+ border.right + handle, border.top + handle);
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
+ window_border.left - border.left, window_border.top + height - handle,
+ window_border.left + handle, border.bottom + handle);
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
+ window_border.left + width - handle, window_border.top + height - handle,
+ border.right + handle, border.bottom + handle);
- attributes.x = allocation.x;
- attributes.y = allocation.y;
- attributes.width = allocation.width;
- attributes.height = allocation.height;
- attributes.window_type = GDK_WINDOW_CHILD;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = border.left + handle;
+ rect.height = border.top + handle;
+ region = cairo_region_create_rectangle (&rect);
+ rect.x = border.left;
+ rect.y = border.top;
+ rect.width = handle;
+ rect.height = handle;
+ cairo_region_subtract_rectangle (region, &rect);
+ gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
+ region, 0, 0);
+ cairo_region_destroy (region);
- attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = border.right + handle;
+ rect.height = border.top + handle;
+ region = cairo_region_create_rectangle (&rect);
+ rect.x = 0;
+ rect.y = border.top;
+ rect.width = handle;
+ rect.height = handle;
+ cairo_region_subtract_rectangle (region, &rect);
+ gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
+ region, 0, 0);
+ cairo_region_destroy (region);
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.wclass = GDK_INPUT_OUTPUT;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = border.left + handle;
+ rect.height = border.bottom + handle;
+ region = cairo_region_create_rectangle (&rect);
+ rect.x = border.left;
+ rect.y = 0;
+ rect.width = handle;
+ rect.height = handle;
+ cairo_region_subtract_rectangle (region, &rect);
+ gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
+ region, 0, 0);
+ cairo_region_destroy (region);
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = border.right + handle;
+ rect.height = border.bottom + handle;
+ region = cairo_region_create_rectangle (&rect);
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = handle;
+ rect.height = handle;
+ cairo_region_subtract_rectangle (region, &rect);
+ gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
+ region, 0, 0);
+ cairo_region_destroy (region);
- if (priv->client_decorated && priv->type == GTK_WINDOW_TOPLEVEL)
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
+ }
+ else
{
- GdkCursorType cursor_type[8] = {
- GDK_TOP_LEFT_CORNER,
- GDK_TOP_SIDE,
- GDK_TOP_RIGHT_CORNER,
- GDK_LEFT_SIDE,
- GDK_RIGHT_SIDE,
- GDK_BOTTOM_LEFT_CORNER,
- GDK_BOTTOM_SIDE,
- GDK_BOTTOM_RIGHT_CORNER
- };
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
+ }
- attributes.wclass = GDK_INPUT_ONLY;
- attributes.width = 1;
- attributes.height = 1;
- attributes.event_mask = GDK_BUTTON_PRESS_MASK;
- attributes_mask = GDK_WA_CURSOR;
+ if (resize_v)
+ {
+ gint x, w;
- for (i = 0; i < 8; i++)
+ if (resize_h)
{
- attributes.cursor = gdk_cursor_new (cursor_type[i]);
- priv->border_window[i] = gdk_window_new (gdk_window, &attributes, attributes_mask);
- g_object_unref (attributes.cursor);
-
- gdk_window_show (priv->border_window[i]);
- gtk_widget_register_window (widget, priv->border_window[i]);
+ x = window_border.left + handle;
+ w = width - 2 * handle;
+ }
+ else
+ {
+ x = 0;
+ w = width + window_border.left + window_border.right;
}
- }
- if (priv->transient_parent &&
- gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
- gdk_window_set_transient_for (gdk_window,
- gtk_widget_get_window (GTK_WIDGET (priv->transient_parent)));
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH],
+ x, window_border.top - border.top,
+ w, border.top);
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH],
+ x, window_border.top + height,
+ w, border.bottom);
- if (priv->wm_role)
- gdk_window_set_role (gdk_window, priv->wm_role);
-
- if (!priv->decorated || priv->client_decorated)
- gdk_window_set_decorations (gdk_window, 0);
- else if (priv->custom_title)
- gdk_window_set_decorations (gdk_window, GDK_DECOR_BORDER);
-
- if (!priv->deletable)
- gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
-
- if (gtk_window_get_skip_pager_hint (window))
- gdk_window_set_skip_pager_hint (gdk_window, TRUE);
-
- if (gtk_window_get_skip_taskbar_hint (window))
- gdk_window_set_skip_taskbar_hint (gdk_window, TRUE);
-
- if (gtk_window_get_accept_focus (window))
- gdk_window_set_accept_focus (gdk_window, TRUE);
- else
- gdk_window_set_accept_focus (gdk_window, FALSE);
-
- if (gtk_window_get_focus_on_map (window))
- gdk_window_set_focus_on_map (gdk_window, TRUE);
- else
- gdk_window_set_focus_on_map (gdk_window, FALSE);
-
- if (priv->modal)
- gdk_window_set_modal_hint (gdk_window, TRUE);
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
+ }
else
- gdk_window_set_modal_hint (gdk_window, FALSE);
-
- if (priv->startup_id)
{
-#ifdef GDK_WINDOWING_X11
- if (GDK_IS_X11_WINDOW (gdk_window))
- {
- guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
- if (timestamp != GDK_CURRENT_TIME)
- gdk_x11_window_set_user_time (gdk_window, timestamp);
- }
-#endif
- if (!startup_id_is_fake (priv->startup_id))
- gdk_window_set_startup_id (gdk_window, priv->startup_id);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
}
-#ifdef GDK_WINDOWING_X11
- if (priv->initial_timestamp != GDK_CURRENT_TIME)
+ if (resize_h)
{
- if (GDK_IS_X11_WINDOW (gdk_window))
- gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp);
- }
-#endif
+ gint y, h;
- if (priv->application)
- gtk_application_handle_window_realize (priv->application, window);
+ if (resize_v)
+ {
+ y = window_border.top + handle;
+ h = height - 2 * handle;
+ }
+ else
+ {
+ y = 0;
+ h = height + window_border.top + window_border.bottom;
+ }
- /* Icons */
- gtk_window_realize_icon (window);
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST],
+ window_border.left - border.left, y,
+ border.left, h);
- link = priv->popovers;
+ gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST],
+ window_border.left + width, y,
+ border.right, h);
- while (link)
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_WEST]);
+ gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_EAST]);
+ }
+ else
{
- GtkWindowPopover *popover = link->data;
- link = link->next;
- popover_realize (popover->widget, popover, window);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_WEST]);
+ gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_EAST]);
}
- check_scale_changed (window);
-}
+shape:
+ /* we also update the input shape, which makes it so that clicks
+ * outside the border windows go through
+ */
-static void
-popover_unrealize (GtkWidget *widget,
- GtkWindowPopover *popover,
- GtkWindow *window)
-{
- gtk_widget_unregister_window (GTK_WIDGET (window), popover->window);
- gtk_widget_unrealize (popover->widget);
- gdk_window_destroy (popover->window);
- popover->window = NULL;
+ if (priv->type != GTK_WINDOW_POPUP)
+ subtract_borders (&window_border, &border);
+
+ rect.x = window_border.left;
+ rect.y = window_border.top;
+ rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right;
+ rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom;
+ region = cairo_region_create_rectangle (&rect);
+ gtk_widget_input_shape_combine_region (widget, region);
+ cairo_region_destroy (region);
}
static void
-gtk_window_unrealize (GtkWidget *widget)
+update_shadow_width (GtkWindow *window,
+ GtkBorder *border)
{
- GtkWindow *window = GTK_WINDOW (widget);
- GtkWindowPrivate *priv = window->priv;
- GtkWindowGeometryInfo *info;
- GList *link;
- gint i;
-
- /* On unrealize, we reset the size of the window such
- * that we will re-apply the default sizing stuff
- * next time we show the window.
- *
- * Default positioning is reset on unmap, instead of unrealize.
- */
- priv->need_default_size = TRUE;
- info = gtk_window_get_geometry_info (window, FALSE);
- if (info)
- {
- info->resize_width = -1;
- info->resize_height = -1;
- info->last.configure_request.x = 0;
- info->last.configure_request.y = 0;
- info->last.configure_request.width = -1;
- info->last.configure_request.height = -1;
- /* be sure we reset geom hints on re-realize */
- info->last.flags = 0;
- }
-
- if (priv->popup_menu)
- {
- gtk_widget_destroy (priv->popup_menu);
- priv->popup_menu = NULL;
- }
-
- /* Icons */
- gtk_window_unrealize_icon (window);
-
- if (priv->border_window[0] != NULL)
- {
- for (i = 0; i < 8; i++)
- {
- gtk_widget_unregister_window (widget, priv->border_window[i]);
- gdk_window_destroy (priv->border_window[i]);
- priv->border_window[i] = NULL;
- }
- }
-
- link = priv->popovers;
-
- while (link)
- {
- GtkWindowPopover *popover = link->data;
- link = link->next;
- popover_unrealize (popover->widget, popover, window);
- }
+ GdkWindow *gdk_window;
- GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
+ gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
- priv->hardcoded_window = NULL;
+ if (gdk_window)
+ gdk_window_set_shadow_width (gdk_window,
+ border->left,
+ border->right,
+ border->top,
+ border->bottom);
}
static void
-sum_borders (GtkBorder *one,
- GtkBorder *two)
+corner_rect (cairo_rectangle_int_t *rect,
+ const GtkCssValue *value)
{
- one->top += two->top;
- one->right += two->right;
- one->bottom += two->bottom;
- one->left += two->left;
+ rect->width = _gtk_css_corner_value_get_x (value, 100);
+ rect->height = _gtk_css_corner_value_get_y (value, 100);
}
static void
-max_borders (GtkBorder *one,
- GtkBorder *two)
+subtract_corners_from_region (cairo_region_t *region,
+ cairo_rectangle_int_t *extents,
+ GtkStyleContext *context)
{
- one->top = MAX (one->top, two->top);
- one->right = MAX (one->right, two->right);
- one->bottom = MAX (one->bottom, two->bottom);
- one->left = MAX (one->left, two->left);
-}
+ cairo_rectangle_int_t rect;
-static void
-subtract_borders (GtkBorder *one,
- GtkBorder *two)
-{
- one->top -= two->top;
- one->right -= two->right;
- one->bottom -= two->bottom;
- one->left -= two->left;
+ gtk_style_context_save (context);
+ add_window_frame_style_class (context);
+
+ corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS));
+ rect.x = extents->x;
+ rect.y = extents->y;
+ cairo_region_subtract_rectangle (region, &rect);
+
+ corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS));
+ rect.x = extents->x + extents->width - rect.width;
+ rect.y = extents->y;
+ cairo_region_subtract_rectangle (region, &rect);
+
+ corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS));
+ rect.x = extents->x;
+ rect.y = extents->y + extents->height - rect.height;
+ cairo_region_subtract_rectangle (region, &rect);
+
+ corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS));
+ rect.x = extents->x + extents->width - rect.width;
+ rect.y = extents->y + extents->height - rect.height;
+ cairo_region_subtract_rectangle (region, &rect);
+
+ gtk_style_context_restore (context);
}
static void
-add_window_frame_style_class (GtkStyleContext *context)
+update_opaque_region (GtkWindow *window,
+ GtkBorder *border,
+ const GtkAllocation *allocation)
{
- gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
- gtk_style_context_add_class (context, "window-frame");
+ GtkWidget *widget = GTK_WIDGET (window);
+ cairo_region_t *opaque_region;
+ GtkStyleContext *context;
+ gboolean is_opaque = FALSE;
+
+ if (!gtk_widget_get_realized (widget))
+ return;
+
+ context = gtk_widget_get_style_context (widget);
+
+ if (!gtk_widget_get_app_paintable (widget))
+ {
+ const GdkRGBA *color;
+ color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
+ is_opaque = (color->alpha >= 1.0);
+ }
+
+ if (is_opaque)
+ {
+ cairo_rectangle_int_t rect;
+
+ rect.x = border->left;
+ rect.y = border->top;
+ rect.width = allocation->width - border->left - border->right;
+ rect.height = allocation->height - border->top - border->bottom;
+
+ opaque_region = cairo_region_create_rectangle (&rect);
+
+ subtract_corners_from_region (opaque_region, &rect, context);
+ }
+ else
+ {
+ opaque_region = NULL;
+ }
+
+ gdk_window_set_opaque_region (gtk_widget_get_window (widget), opaque_region);
+
+ cairo_region_destroy (opaque_region);
}
static void
-update_window_style_classes (GtkWindow *window)
+update_realized_window_properties (GtkWindow *window,
+ GtkAllocation *child_allocation,
+ GtkBorder *window_border)
{
GtkWindowPrivate *priv = window->priv;
- GtkStyleContext *context;
- context = gtk_widget_get_style_context (GTK_WIDGET (window));
+ if (priv->client_decorated)
+ update_shadow_width (window, window_border);
- if (priv->tiled)
- gtk_style_context_add_class (context, "tiled");
- else
- gtk_style_context_remove_class (context, "tiled");
+ update_opaque_region (window, window_border, child_allocation);
- if (priv->maximized)
- gtk_style_context_add_class (context, "maximized");
- else
- gtk_style_context_remove_class (context, "maximized");
+ if (gtk_widget_is_toplevel (GTK_WIDGET (window)))
+ update_border_windows (window);
}
static void
-get_shadow_width (GtkWidget *widget,
- GtkBorder *shadow_width)
+gtk_window_realize (GtkWidget *widget)
{
- GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
- GtkBorder border = { 0 };
- GtkBorder d = { 0 };
- GtkBorder margin;
- GtkStyleContext *context;
- GtkStateFlags state, s;
- GtkCssValue *shadows;
+ GtkAllocation allocation;
+ GtkAllocation child_allocation;
+ GtkWindow *window;
+ GdkWindow *parent_window;
+ GdkWindow *gdk_window;
+ GdkWindowAttr attributes;
+ GtkBorder window_border;
+ gint attributes_mask;
+ GtkWindowPrivate *priv;
gint i;
+ GList *link;
- *shadow_width = border;
+ window = GTK_WINDOW (widget);
+ priv = window->priv;
- if (!priv->decorated ||
- !priv->client_decorated)
- return;
+ if (!priv->client_decorated && gtk_window_should_use_csd (window))
+ create_decoration (widget);
- if (priv->maximized ||
- priv->fullscreen ||
- priv->tiled)
- return;
+ gtk_widget_get_allocation (widget, &allocation);
- state = gtk_widget_get_state_flags (widget);
- context = gtk_widget_get_style_context (widget);
+ if (gtk_widget_get_parent_window (widget))
+ {
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
- gtk_style_context_save (context);
- add_window_frame_style_class (context);
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.window_type = GDK_WINDOW_CHILD;
- /* We don't want windows to jump as they go to backdrop,
- * therefore we use the maximum of the decoration sizes
- * for focused and unfocused.
- */
- for (i = 0; i < 2; i++)
- {
- if (i == 0)
- s = state & ~GTK_STATE_FLAG_BACKDROP;
- else
- s = state | GTK_STATE_FLAG_BACKDROP;
+ attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
- /* Always sum border + padding */
- gtk_style_context_get_border (context, s, &border);
- gtk_style_context_get_padding (context, s, &d);
- sum_borders (&d, &border);
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.wclass = GDK_INPUT_OUTPUT;
- /* Calculate the size of the drop shadows ... */
- gtk_style_context_set_state (context, s);
- shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW);
- _gtk_css_shadows_value_get_extents (shadows, &border);
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
- if (priv->type != GTK_WINDOW_POPUP)
- {
- /* ... and compare it to the margin size, which we use for resize grips */
- gtk_style_context_get_margin (context, s, &margin);
- max_borders (&border, &margin);
- }
+ gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+ gtk_widget_set_window (widget, gdk_window);
+ gtk_widget_register_window (widget, gdk_window);
+ gtk_widget_set_realized (widget, TRUE);
- sum_borders (&d, &border);
- max_borders (shadow_width, &d);
+ return;
}
- gtk_style_context_restore (context);
-}
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
-/* We're placing 8 input-only windows around
- * the window content as resize handles, as
- * follows:
- *
- * +-----------------------------------+
- * | +------+-----------------+------+ |
- * | | | | | |
- * | | +--+-----------------+--+ | |
- * | | | | | |
- * | +---+ +---+ |
- * | | | | | |
- * | | | | | |
- * | | | | | |
- * | +---+ +---+ |
- * | | | | | |
- * | | +--+-----------------+--+ | |
- * | | | | | |
- * | +------+-----------------+------+ |
- * +-----------------------------------+
- *
- * The corner windows are shaped to allow them
- * to extend into the edges. If the window is
- * not resizable in both dimensions, we hide
- * the corner windows and the edge windows in
- * the nonresizable dimension and make the
- * remaining edge window extend all the way.
- *
- * The border are where we place the resize handles
- * is also used to draw the window shadow, which may
- * extend out farther than the handles (or the other
- * way around).
- */
-static void
-update_border_windows (GtkWindow *window)
-{
- GtkWidget *widget = (GtkWidget *)window;
- GtkWindowPrivate *priv = window->priv;
- gboolean resize_h, resize_v;
- gint handle;
- cairo_region_t *region;
- cairo_rectangle_int_t rect;
- gint width, height;
- GtkBorder border;
- GtkBorder window_border;
- GtkStyleContext *context;
- GtkStateFlags state;
+ /* ensure widget tree is properly size allocated */
+ if (allocation.x == -1 &&
+ allocation.y == -1 &&
+ allocation.width == 1 &&
+ allocation.height == 1)
+ {
+ gint w, h;
- if (!priv->client_decorated)
- return;
+ allocation.x = 0;
+ allocation.y = 0;
- state = gtk_widget_get_state_flags (widget);
- context = gtk_widget_get_style_context (widget);
+ gtk_window_guess_default_size (window, &allocation.width, &allocation.height);
+ gtk_window_get_remembered_size (window, &w, &h);
+ allocation.width = MAX (allocation.width, w);
+ allocation.height = MAX (allocation.height, h);
+ if (allocation.width == 0 || allocation.height == 0)
+ {
+ /* non-empty window */
+ allocation.width = 200;
+ allocation.height = 200;
+ }
+ gtk_widget_size_allocate (widget, &allocation);
- gtk_style_context_save (context);
- add_window_frame_style_class (context);
- gtk_style_context_set_state (context, state);
- gtk_style_context_get_margin (context, state, &border);
- gtk_widget_style_get (widget,
- "decoration-resize-handle", &handle,
- NULL);
- gtk_style_context_restore (context);
- get_shadow_width (widget, &window_border);
+ _gtk_container_queue_resize (GTK_CONTAINER (widget));
- if (priv->border_window[0] == NULL)
- goto shape;
+ g_return_if_fail (!gtk_widget_get_realized (widget));
+ }
- if (!priv->resizable ||
- priv->tiled ||
- priv->fullscreen ||
- priv->maximized)
+ if (priv->hardcoded_window)
{
- resize_h = resize_v = FALSE;
+ gdk_window = priv->hardcoded_window;
+ gtk_widget_get_allocation (widget, &allocation);
+ gdk_window_resize (gdk_window, allocation.width, allocation.height);
}
else
{
- resize_h = resize_v = TRUE;
- if (priv->geometry_info)
+ switch (priv->type)
{
- GdkGeometry *geometry = &priv->geometry_info->geometry;
- GdkWindowHints flags = priv->geometry_info->mask;
-
- if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE))
- {
- resize_h = geometry->min_width != geometry->max_width;
- resize_v = geometry->min_height != geometry->max_height;
- }
+ case GTK_WINDOW_TOPLEVEL:
+ attributes.window_type = GDK_WINDOW_TOPLEVEL;
+ break;
+ case GTK_WINDOW_POPUP:
+ attributes.window_type = GDK_WINDOW_TEMP;
+ break;
+ default:
+ g_warning (G_STRLOC": Unknown window type %d!", priv->type);
+ break;
}
- }
- width = gtk_widget_get_allocated_width (widget) - (window_border.left + window_border.right);
- height = gtk_widget_get_allocated_height (widget) - (window_border.top + window_border.bottom);
+#ifdef GDK_WINDOWING_WAYLAND
+ if (priv->use_subsurface &&
+ GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
+ attributes.window_type = GDK_WINDOW_SUBSURFACE;
+#endif
- if (resize_h && resize_v)
- {
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
- window_border.left - border.left, window_border.top - border.top,
- border.left + handle, border.top + handle);
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
- window_border.left + width - handle, window_border.top - border.top,
- border.right + handle, border.top + handle);
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
- window_border.left - border.left, window_border.top + height - handle,
- window_border.left + handle, border.bottom + handle);
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
- window_border.left + width - handle, window_border.top + height - handle,
- border.right + handle, border.bottom + handle);
+ attributes.title = priv->title;
+ attributes.wmclass_name = priv->wmclass_name;
+ attributes.wmclass_class = priv->wmclass_class;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
- rect.x = 0;
- rect.y = 0;
- rect.width = border.left + handle;
- rect.height = border.top + handle;
- region = cairo_region_create_rectangle (&rect);
- rect.x = border.left;
- rect.y = border.top;
- rect.width = handle;
- rect.height = handle;
- cairo_region_subtract_rectangle (region, &rect);
- gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
- region, 0, 0);
- cairo_region_destroy (region);
+ attributes_mask = 0;
+ parent_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
- rect.x = 0;
- rect.y = 0;
- rect.width = border.right + handle;
- rect.height = border.top + handle;
- region = cairo_region_create_rectangle (&rect);
- rect.x = 0;
- rect.y = border.top;
- rect.width = handle;
- rect.height = handle;
- cairo_region_subtract_rectangle (region, &rect);
- gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
- region, 0, 0);
- cairo_region_destroy (region);
+ gtk_widget_get_allocation (widget, &allocation);
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_EXPOSURE_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_FOCUS_CHANGE_MASK |
+ GDK_STRUCTURE_MASK);
- rect.x = 0;
- rect.y = 0;
- rect.width = border.left + handle;
- rect.height = border.bottom + handle;
- region = cairo_region_create_rectangle (&rect);
- rect.x = border.left;
- rect.y = 0;
- rect.width = handle;
- rect.height = handle;
- cairo_region_subtract_rectangle (region, &rect);
- gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
- region, 0, 0);
- cairo_region_destroy (region);
+ if (priv->decorated &&
+ (priv->client_decorated || priv->custom_title))
+ attributes.event_mask |= GDK_POINTER_MOTION_MASK;
- rect.x = 0;
- rect.y = 0;
- rect.width = border.right + handle;
- rect.height = border.bottom + handle;
- region = cairo_region_create_rectangle (&rect);
- rect.x = 0;
- rect.y = 0;
- rect.width = handle;
- rect.height = handle;
- cairo_region_subtract_rectangle (region, &rect);
- gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
- region, 0, 0);
- cairo_region_destroy (region);
+ attributes.type_hint = priv->type_hint;
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
- }
- else
- {
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]);
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]);
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]);
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]);
+ attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT;
+ attributes_mask |= (priv->title ? GDK_WA_TITLE : 0);
+ attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0);
+
+ gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask);
}
- if (resize_v)
+ gtk_widget_set_window (widget, gdk_window);
+ gtk_widget_register_window (widget, gdk_window);
+ gtk_widget_set_realized (widget, TRUE);
+
+ /* We don't need to set a background on the GdkWindow; with decorations
+ * we draw the background ourself
+ */
+ if (!priv->client_decorated)
+ gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window);
+
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.window_type = GDK_WINDOW_CHILD;
+
+ attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.wclass = GDK_INPUT_OUTPUT;
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+ if (priv->client_decorated && priv->type == GTK_WINDOW_TOPLEVEL)
{
- gint x, w;
+ GdkCursorType cursor_type[8] = {
+ GDK_TOP_LEFT_CORNER,
+ GDK_TOP_SIDE,
+ GDK_TOP_RIGHT_CORNER,
+ GDK_LEFT_SIDE,
+ GDK_RIGHT_SIDE,
+ GDK_BOTTOM_LEFT_CORNER,
+ GDK_BOTTOM_SIDE,
+ GDK_BOTTOM_RIGHT_CORNER
+ };
- if (resize_h)
- {
- x = window_border.left + handle;
- w = width - 2 * handle;
- }
- else
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.width = 1;
+ attributes.height = 1;
+ attributes.event_mask = GDK_BUTTON_PRESS_MASK;
+ attributes_mask = GDK_WA_CURSOR;
+
+ for (i = 0; i < 8; i++)
{
- x = 0;
- w = width + window_border.left + window_border.right;
+ attributes.cursor = gdk_cursor_new (cursor_type[i]);
+ priv->border_window[i] = gdk_window_new (gdk_window, &attributes, attributes_mask);
+ g_object_unref (attributes.cursor);
+
+ gdk_window_show (priv->border_window[i]);
+ gtk_widget_register_window (widget, priv->border_window[i]);
}
+ }
+
+ if (priv->transient_parent &&
+ gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
+ gdk_window_set_transient_for (gdk_window,
+ gtk_widget_get_window (GTK_WIDGET (priv->transient_parent)));
+
+ if (priv->wm_role)
+ gdk_window_set_role (gdk_window, priv->wm_role);
+
+ if (!priv->decorated || priv->client_decorated)
+ gdk_window_set_decorations (gdk_window, 0);
+ else if (priv->custom_title)
+ gdk_window_set_decorations (gdk_window, GDK_DECOR_BORDER);
+
+ if (!priv->deletable)
+ gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
+
+ if (gtk_window_get_skip_pager_hint (window))
+ gdk_window_set_skip_pager_hint (gdk_window, TRUE);
+
+ if (gtk_window_get_skip_taskbar_hint (window))
+ gdk_window_set_skip_taskbar_hint (gdk_window, TRUE);
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH],
- x, window_border.top - border.top,
- w, border.top);
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH],
- x, window_border.top + height,
- w, border.bottom);
+ if (gtk_window_get_accept_focus (window))
+ gdk_window_set_accept_focus (gdk_window, TRUE);
+ else
+ gdk_window_set_accept_focus (gdk_window, FALSE);
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
- }
+ if (gtk_window_get_focus_on_map (window))
+ gdk_window_set_focus_on_map (gdk_window, TRUE);
else
- {
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
- }
+ gdk_window_set_focus_on_map (gdk_window, FALSE);
- if (resize_h)
- {
- gint y, h;
+ if (priv->modal)
+ gdk_window_set_modal_hint (gdk_window, TRUE);
+ else
+ gdk_window_set_modal_hint (gdk_window, FALSE);
- if (resize_v)
- {
- y = window_border.top + handle;
- h = height - 2 * handle;
- }
- else
+ if (priv->startup_id)
+ {
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_WINDOW (gdk_window))
{
- y = 0;
- h = height + window_border.top + window_border.bottom;
+ guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
+ if (timestamp != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (gdk_window, timestamp);
}
-
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST],
- window_border.left - border.left, y,
- border.left, h);
-
- gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST],
- window_border.left + width, y,
- border.right, h);
-
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_WEST]);
- gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_EAST]);
+#endif
+ if (!startup_id_is_fake (priv->startup_id))
+ gdk_window_set_startup_id (gdk_window, priv->startup_id);
}
- else
+
+#ifdef GDK_WINDOWING_X11
+ if (priv->initial_timestamp != GDK_CURRENT_TIME)
{
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_WEST]);
- gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_EAST]);
+ if (GDK_IS_X11_WINDOW (gdk_window))
+ gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp);
}
+#endif
-shape:
- /* we also update the input shape, which makes it so that clicks
- * outside the border windows go through
- */
+ child_allocation.x = 0;
+ child_allocation.y = 0;
+ child_allocation.width = allocation.width;
+ child_allocation.height = allocation.height;
- if (priv->type != GTK_WINDOW_POPUP)
- subtract_borders (&window_border, &border);
+ get_shadow_width (widget, &window_border);
- rect.x = window_border.left;
- rect.y = window_border.top;
- rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right;
- rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom;
- region = cairo_region_create_rectangle (&rect);
- gtk_widget_input_shape_combine_region (widget, region);
- cairo_region_destroy (region);
-}
+ update_realized_window_properties (window, &child_allocation, &window_border);
-static void
-update_shadow_width (GtkWindow *window,
- GtkBorder *border)
-{
- GdkWindow *gdk_window;
+ if (priv->application)
+ gtk_application_handle_window_realize (priv->application, window);
- gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+ /* Icons */
+ gtk_window_realize_icon (window);
- if (gdk_window)
- gdk_window_set_shadow_width (gdk_window,
- border->left,
- border->right,
- border->top,
- border->bottom);
+ link = priv->popovers;
+
+ while (link)
+ {
+ GtkWindowPopover *popover = link->data;
+ link = link->next;
+ popover_realize (popover->widget, popover, window);
+ }
+
+ check_scale_changed (window);
}
static void
-corner_rect (cairo_rectangle_int_t *rect,
- const GtkCssValue *value)
+popover_unrealize (GtkWidget *widget,
+ GtkWindowPopover *popover,
+ GtkWindow *window)
{
- rect->width = _gtk_css_corner_value_get_x (value, 100);
- rect->height = _gtk_css_corner_value_get_y (value, 100);
+ gtk_widget_unregister_window (GTK_WIDGET (window), popover->window);
+ gtk_widget_unrealize (popover->widget);
+ gdk_window_destroy (popover->window);
+ popover->window = NULL;
}
static void
-subtract_corners_from_region (cairo_region_t *region,
- cairo_rectangle_int_t *extents,
- GtkStyleContext *context)
+gtk_window_unrealize (GtkWidget *widget)
{
- cairo_rectangle_int_t rect;
+ GtkWindow *window = GTK_WINDOW (widget);
+ GtkWindowPrivate *priv = window->priv;
+ GtkWindowGeometryInfo *info;
+ GList *link;
+ gint i;
- gtk_style_context_save (context);
- add_window_frame_style_class (context);
+ /* On unrealize, we reset the size of the window such
+ * that we will re-apply the default sizing stuff
+ * next time we show the window.
+ *
+ * Default positioning is reset on unmap, instead of unrealize.
+ */
+ priv->need_default_size = TRUE;
+ info = gtk_window_get_geometry_info (window, FALSE);
+ if (info)
+ {
+ info->resize_width = -1;
+ info->resize_height = -1;
+ info->last.configure_request.x = 0;
+ info->last.configure_request.y = 0;
+ info->last.configure_request.width = -1;
+ info->last.configure_request.height = -1;
+ /* be sure we reset geom hints on re-realize */
+ info->last.flags = 0;
+ }
- corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS));
- rect.x = extents->x;
- rect.y = extents->y;
- cairo_region_subtract_rectangle (region, &rect);
+ if (priv->popup_menu)
+ {
+ gtk_widget_destroy (priv->popup_menu);
+ priv->popup_menu = NULL;
+ }
- corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS));
- rect.x = extents->x + extents->width - rect.width;
- rect.y = extents->y;
- cairo_region_subtract_rectangle (region, &rect);
+ /* Icons */
+ gtk_window_unrealize_icon (window);
- corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS));
- rect.x = extents->x;
- rect.y = extents->y + extents->height - rect.height;
- cairo_region_subtract_rectangle (region, &rect);
+ if (priv->border_window[0] != NULL)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ gtk_widget_unregister_window (widget, priv->border_window[i]);
+ gdk_window_destroy (priv->border_window[i]);
+ priv->border_window[i] = NULL;
+ }
+ }
- corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS));
- rect.x = extents->x + extents->width - rect.width;
- rect.y = extents->y + extents->height - rect.height;
- cairo_region_subtract_rectangle (region, &rect);
+ link = priv->popovers;
- gtk_style_context_restore (context);
+ while (link)
+ {
+ GtkWindowPopover *popover = link->data;
+ link = link->next;
+ popover_unrealize (popover->widget, popover, window);
+ }
+
+ GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
+
+ priv->hardcoded_window = NULL;
}
static void
-update_opaque_region (GtkWindow *window,
- GtkBorder *border,
- const GtkAllocation *allocation)
+update_window_style_classes (GtkWindow *window)
{
- GtkWidget *widget = GTK_WIDGET (window);
- cairo_region_t *opaque_region;
+ GtkWindowPrivate *priv = window->priv;
GtkStyleContext *context;
- gboolean is_opaque = FALSE;
-
- if (!gtk_widget_get_realized (widget))
- return;
-
- context = gtk_widget_get_style_context (widget);
-
- if (!gtk_widget_get_app_paintable (widget))
- {
- const GdkRGBA *color;
- color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
- is_opaque = (color->alpha >= 1.0);
- }
-
- if (is_opaque)
- {
- cairo_rectangle_int_t rect;
-
- rect.x = border->left;
- rect.y = border->top;
- rect.width = allocation->width - border->left - border->right;
- rect.height = allocation->height - border->top - border->bottom;
- opaque_region = cairo_region_create_rectangle (&rect);
+ context = gtk_widget_get_style_context (GTK_WIDGET (window));
- subtract_corners_from_region (opaque_region, &rect, context);
- }
+ if (priv->tiled)
+ gtk_style_context_add_class (context, "tiled");
else
- {
- opaque_region = NULL;
- }
-
- gdk_window_set_opaque_region (gtk_widget_get_window (widget), opaque_region);
+ gtk_style_context_remove_class (context, "tiled");
- cairo_region_destroy (opaque_region);
+ if (priv->maximized)
+ gtk_style_context_add_class (context, "maximized");
+ else
+ gtk_style_context_remove_class (context, "maximized");
}
static void
gtk_widget_set_allocation (widget, allocation);
- get_shadow_width (widget, &window_border);
- border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
-
child_allocation.x = 0;
child_allocation.y = 0;
child_allocation.width = allocation->width;
child_allocation.height = allocation->height;
- priv->title_height = 0;
+ get_shadow_width (widget, &window_border);
- if (priv->client_decorated)
- update_shadow_width (window, &window_border);
+ if (gtk_widget_get_realized (widget))
+ update_realized_window_properties (window, &child_allocation, &window_border);
- update_opaque_region (window, &window_border, &child_allocation);
+ priv->title_height = 0;
if (priv->title_box != NULL &&
gtk_widget_get_visible (priv->title_box) &&
priv->title_height;
}
- if (gtk_widget_get_realized (widget))
+ if (!gtk_widget_is_toplevel (widget) && gtk_widget_get_realized (widget))
{
- /* If it's not a toplevel we're embedded, we need to resize
- * the window's window and skip the grip.
- */
- if (!gtk_widget_is_toplevel (widget))
- {
- gdk_window_move_resize (gtk_widget_get_window (widget),
- allocation->x, allocation->y,
- allocation->width, allocation->height);
- }
- else
- {
- update_border_windows (window);
- }
+ gdk_window_move_resize (gtk_widget_get_window (widget),
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
}
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
child_allocation.x += border_width;
child_allocation.y += border_width;
child_allocation.width = MAX (1, child_allocation.width - border_width * 2);